package LauncherGUI;

import Simulator.Simulator;
import Visualisation.DrawSimulation;

import java.applet.Applet;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.util.Date;
import java.util.StringTokenizer;

import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public	class Visual   implements ActionListener, Runnable {

	//	private static Visual myVisual;
	private JPanel canvas;
	private DataInputStream dis = null;
	private final int ARRAY =1620;
	private int[] carArray = new int[ARRAY];	
	private int position;
	private DrawSimulation car = null,carGraph;
	private JSlider slider;

	private final int SLIDER_RANGE=120;
	private int value=SLIDER_RANGE/2;
	private JLabel minLabel;
	private JButton open, play,exit; 
	JTextArea infoLabel;

	boolean Finish = false;

	private int time;
	private String fileName=null;

	//======================COMPONENTS FOR SIMULATE PANEL==================

	private JTextField textNumCars, textMaxSpeed, textLengthRoad, textNumIterations, textProbability, textIncomingProbability, textOutputFile;
	private JButton simulateButton;
	private JTextArea log;
	private JScrollPane logPane;
	private JPanel controlPanel;
	private JPanel simulatePanel;

	//================Simulation variables
	private int numCars;
	private int maxSpeed;
	private int iterations;
	private int lengthRoad;

	JLabel label = new JLabel();
	JPanel graphPanel = new JPanel();
	JFrame frame =new JFrame();
	private JLabel iterationLabel;
	Thread t;
	Object runLock = new Object();
	volatile boolean shouldRun = false;
	Boolean EOF = false;

	Date date = new Date();

	public static void main(String[] arg){


		try {
			new Visual();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}


	}

	public Visual() throws InterruptedException{


		canvas=new JPanel();
		open = new JButton("Select File");
		play = new JButton("Start");

		exit = new JButton("Exit");

		iterationLabel = new JLabel();


		open.addActionListener(this);
		play.addActionListener(this);
		exit.addActionListener(this);



		frame.setVisible(true);
		frame.setSize(1200, 300);
		frame.setLocationRelativeTo(null);

		slider = new JSlider(0,SLIDER_RANGE,0);

		slider.setValue(value);

		slider.addChangeListener(new ChangeAction());

		frame.setLayout(new GridLayout(2,0));

		//==================CONTROL PANEL SETUP=============================

		controlPanel = new JPanel();

		JLabel title = new JLabel("TRAFFIC SIMULATION");

		controlPanel.add(title);

		controlPanel.add(open);
		controlPanel.add(play);



		controlPanel.add(exit);
		JPanel sliderPanel = new JPanel();

		infoLabel = new JTextArea(10,30);
		infoLabel.setBackground(controlPanel.getBackground());
		infoLabel.setBorder(BorderFactory.createLineBorder(Color.GRAY));

		minLabel = new JLabel("Minimum");
		sliderPanel.add(minLabel);
		sliderPanel.add(slider);
		sliderPanel.add(new JLabel("Maximum"));
		sliderPanel.add(label);
		sliderPanel.setBorder(BorderFactory.createLineBorder(Color.GRAY));
		controlPanel.add(sliderPanel);
		JLabel x_axes = new JLabel("X-Axes");
		graphPanel.add(x_axes);
		x_axes.setLocation(graphPanel.getWidth()/2, controlPanel.getHeight());
		controlPanel.add(graphPanel);

		controlPanel.setBorder(BorderFactory.createLineBorder(Color.GREEN, 5));
		graphPanel.setBorder(BorderFactory.createLineBorder(Color.GREEN, 5));
		graphPanel.setBorder(BorderFactory.createLineBorder(Color.gray));
		graphPanel.setBorder(BorderFactory.createLineBorder(Color.GREEN));



		//==================SIMULATE PANEL SETUP============================

		simulatePanel = new JPanel();
		simulatePanel.setLayout(new GridLayout(8,2));

		simulatePanel.setOpaque(true);
		simulatePanel.setBorder(BorderFactory.createLineBorder(Color.GREEN, 5));

		textNumCars = new JTextField(8);
		textNumCars.setText("100");
		simulatePanel.add(new JLabel("Number of Cars: "));
		simulatePanel.add(textNumCars);



		textMaxSpeed = new JTextField(8);
		textMaxSpeed.setText("10");
		simulatePanel.add(new JLabel("Maximum Speed: "));
		simulatePanel.add(textMaxSpeed);


		textLengthRoad = new JTextField(8);
		textLengthRoad.setText("1000");
		simulatePanel.add(new JLabel("Length of the road: "));
		simulatePanel.add(textLengthRoad);

		textNumIterations = new JTextField(8);
		textNumIterations.setText("1000");
		simulatePanel.add(new JLabel("Number of iterations: "));
		simulatePanel.add(textNumIterations);

		textProbability = new JTextField(8);
		textProbability.setText("0.7");
		simulatePanel.add(new JLabel("Probability of reduce speed: "));
		simulatePanel.add(textProbability);

		textIncomingProbability = new JTextField(8);
		textIncomingProbability.setText("0.8");
		simulatePanel.add(new JLabel("Incoming Car Probability: "));
		simulatePanel.add(textIncomingProbability);

		textOutputFile = new JTextField(8);
		textOutputFile.setText("out.dat");
		JPanel outputFilePanel = new JPanel();
		outputFilePanel.setLayout(new GridLayout(0,1));
		outputFilePanel.add(textOutputFile);
		//selectFileButton = new JButton("Select");
	//	selectFileButton.addActionListener(this);
		//outputFilePanel.add(selectFileButton);
		simulatePanel.add(new JLabel("Output Filename: "));
		simulatePanel.add(outputFilePanel);

		simulateButton = new JButton("Simulate");
		simulateButton.addActionListener(this);
		simulatePanel.add(simulateButton);

		log = new JTextArea();
		log.setRows(5);
		log.setEditable(false);

		logPane = new JScrollPane(log);
		simulatePanel.add(logPane);	


		JPanel simControlPanel = new JPanel(new GridLayout(0,3));
		simControlPanel.setBorder(BorderFactory.createLineBorder(Color.BLUE, 5));

		controlPanel.add(infoLabel);
		simControlPanel.add(simulatePanel);
		simControlPanel.add(controlPanel);
		simControlPanel.add(graphPanel);
		frame.add(simControlPanel);
		canvas.add(iterationLabel);
		frame.add(canvas);
		frame.setExtendedState(frame.getExtendedState()|JFrame.MAXIMIZED_BOTH);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		car =new DrawSimulation(canvas);
		play.setEnabled(false);
		
		
		
		
		int	fontSize=controlPanel.getWidth()/12;
			Font	font = new Font(Font.SERIF,Font.CENTER_BASELINE,fontSize );
			title.setFont(font);
		}

	public class ChangeAction implements ChangeListener{
		public void stateChanged(ChangeEvent e) {

			value = SLIDER_RANGE-slider.getValue();
			label.setText(Integer.toString(slider.getValue()));
		}
	}

	public void speed_control(){
		safeSleep(value);
		canvas.validate();
	}


	public void start() {
		if (t == null ) {
			shouldRun = true;

			t = new Thread(this);

			t.start();
		}else {
			synchronized(runLock) {



				t = new Thread(this);
				shouldRun = true;
				t.start();
				runLock.notify();
			}
		}
	} // end start



	public synchronized void  run(){
		//for(;;){

		//	synchronized(runLock){
		if(shouldRun){
			updateAnimation();
		}
		//}
		//}
	}
	int panelHeight;
	@SuppressWarnings("deprecation")
	public void updateAnimation(){
		try {
			File f = new File(fileName);
			FileInputStream fis = new FileInputStream(f);
			BufferedInputStream bis = new BufferedInputStream(fis);
			dis = new DataInputStream(bis);
			String str;

			while ((str = dis.readLine()) != null & !EOF ) {

				iterationLabel.setText(Integer.toString(time));
				StringTokenizer st = new StringTokenizer(str, "\t");                   

				if(str.startsWith("#")){

					String info = str.replaceAll("#", " ");
					//infoLabel.append("\n"+info);
					//infoLabel.setFont(new Font( Font.SANS_SERIF,Font.PLAIN, 14));

				}else{
					++time;
					for(int i = 0; i < carArray.length; i++){
						if(car!=null || carArray[i]>0){
							car.remove(i);
						}
						carArray[i]=0;	
						if(i > ARRAY & car!=null)
							car.remove(i);
					}

					while(st.hasMoreTokens()){
						String mystring = st.nextToken().replaceAll("-", "0");
						position=Integer.valueOf(mystring).intValue();
						carArray[position]=position;

					}
					panelHeight = graphPanel.getHeight();
					for(int x=0; x<carArray.length;x++){	

						if(carArray[x]>0){
							//car =new DrawSimulation(canvas);

							car.draw(carArray[x]*8);

							carGraph = new DrawSimulation(graphPanel);
							carGraph.drawPlot(carArray[x]);

							int more = 1;
							int y = panelHeight - time;

							if(y > 0){

								carGraph.plot(x,y);
							}else if(y==0){
								graphPanel.repaint();
							}else if(y+graphPanel.getHeight()==0){

								graphPanel.repaint();
							}
							else {

								if(y + graphPanel.getHeight()< 0){
									more++;
								}
								y= y + graphPanel.getHeight()*more;

								if(y<0){
									y = y +graphPanel.getHeight();
									carGraph.plot(x, y);
								}else if(y==0){
									graphPanel.repaint();
								}else carGraph.plot(x, y);

							}
							if(y<0){
								y = y +graphPanel.getHeight();
								carGraph.plot(x, y);

							}else if(y==0){
								graphPanel.repaint();
							}
							if(y==0){
								graphPanel.repaint();
							}else if (y<0){
								y = y +graphPanel.getHeight();
								carGraph.plot(x, y);
								label.setText(Integer.valueOf(y).toString());
							}
						}			
					}
					speed_control();
				}
			} 
		} catch (IOException e) {

			System.out.println("Uh oh, got an IOException error: " + e.getMessage());
			shouldRun=false;


		} finally {
			// if the file opened okay, make sure we close it
			if (dis != null) {
				try {
					shouldRun=false;

					dis.close();
					play.setText("Start");
					time=0;



				} catch (IOException ioe) {
					System.out.println("IOException error trying to close the file: " );
				}
			} // end if
		} // end finally
	}
	//JOptionPane.showMessageDialog(new JFrame(), 
	//	"No data file was selected", "Input Error",
	//JOptionPane.ERROR_MESSAGE);





	@SuppressWarnings("deprecation")
	public void chooseFile(){
		//	

		JFileChooser chooser = new JFileChooser();
		chooser.setCurrentDirectory(new File("."));

		chooser.setFileFilter(new javax.swing.filechooser.FileFilter(){
			public boolean accept(File f){
				return f.getName().toLowerCase().endsWith(".dat") || f.isDirectory();
			}

			public String getDescription(){
				return "Data Files";
			}
		});
		int r = chooser.showOpenDialog(new JFrame());
		if(r==JFileChooser.APPROVE_OPTION){
			fileName = chooser.getSelectedFile().getName();
		}
		File f = new File(fileName);
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(f);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		BufferedInputStream bis = new BufferedInputStream(fis);
		dis = new DataInputStream(bis);
		String str;

		try {
			infoLabel.setText("");
			time = 0;
			while ((str = dis.readLine()) != null ) {

				iterationLabel.setText(Integer.toString(time));


				if(str.startsWith("#")){

					String info = str.replaceAll("#", " ");
					infoLabel.append("\n"+info);
					infoLabel.setFont(new Font( Font.SANS_SERIF,Font.PLAIN, 14));
					time=0;
					graphPanel.repaint();

				}else break;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		//time = 0;

		//graphPanel.repaint();
		//
	}



	@SuppressWarnings("deprecation")
	public void actionPerformed(ActionEvent e) {

		if(e.getSource()==open){
			chooseFile();
			if(fileName!=null){
				play.setEnabled(true);

			}

		}
		if(e.getSource()==play){
			if(fileName!=null){
				if(play.getText().equals("Start")){
					start();
					play.setText("Pause");
					graphPanel.repaint();					
				}else if(play.getText().equals("Pause")){
					t.suspend();
					play.setText("Resume");
				}else {
					t.resume();
					play.setText("Pause");
				}
			}else JOptionPane.showMessageDialog(null, 
					"No data file was selected", "Input Error",
					JOptionPane.ERROR_MESSAGE);

		}else if(e.getSource()==exit){

			System.exit(0);
		}

		if (e.getSource()==simulateButton){
			if(Float.parseFloat(textIncomingProbability.getText()) >= 0 & Float.parseFloat(textIncomingProbability.getText()) <= 1){
				if(Float.parseFloat(textProbability.getText()) >= 0 & Float.parseFloat(textProbability.getText()) <= 1){
					if(Integer.parseInt(textLengthRoad.getText()) <= ARRAY){
						if(Integer.parseInt(textNumCars.getText()) < Integer.parseInt(textLengthRoad.getText())/1.25){
							log.append("Starting Simulation");

							numCars = Integer.parseInt(textNumCars.getText());
							maxSpeed = Integer.parseInt(textMaxSpeed.getText());
							iterations = Integer.parseInt(textNumIterations.getText());
							lengthRoad = Integer.parseInt(textLengthRoad.getText());
							float probability;
							float incomingCarProbability;

							probability = Float.parseFloat(textProbability.getText());
							incomingCarProbability = Float.parseFloat(textIncomingProbability.getText());
							String filename = textOutputFile.getText();

							Simulator simulator = new Simulator(numCars,maxSpeed,lengthRoad,probability, incomingCarProbability);

							String d = date.toString();
							d=d.replaceAll(":", "_");
							// Set output file
							PrintWriter outFile = simulator.printToFile(d+"_"+filename);


							outFile.println("#Simulation of traffic on "
									+ date.toString());
							outFile.println("#Number of Cars:\t"+numCars+"\n#Max Speed:\t\t"+maxSpeed
									+"\n#Length of the Road:\t"+lengthRoad+"\n#Slow Down Probability:\t"+probability+
									"\n#Incoming Car Probability:\t"+incomingCarProbability+"\n#Number of Iterations:\t"+iterations);


							simulator.simulate(iterations);

							// close output file
							outFile.close();
							simulator.generateGnuplotScript(filename+ ".script", filename);
							log.append("\nDONE, check output file "+filename+",\nand load script file in gnuplot\n");


						}//else if(e.getSource()==selectFileButton){
							//JFileChooser fc = new JFileChooser();			
							//int returnVal = fc.showSaveDialog(null);
						//	if (returnVal == JFileChooser.APPROVE_OPTION) {
							//	textOutputFile.setText(fc.getSelectedFile().getAbsolutePath());;
						//	}
						//}

						else JOptionPane.showMessageDialog(new JFrame(), 
								"you have excided the maximum number of cars over the length of the road", "Input Error",
								JOptionPane.ERROR_MESSAGE);	
					}else JOptionPane.showMessageDialog(new JFrame(), 
							"You have excided the maximum road length of 1000", "Input Error",
							JOptionPane.ERROR_MESSAGE);	

				}
				else JOptionPane.showMessageDialog(new JFrame(), 
						"Probability to reduce speed must be greater or equal to zero or less or equal to 1", "Input Error",
						JOptionPane.ERROR_MESSAGE);				        
			}
			else JOptionPane.showMessageDialog(new JFrame(), 
					"Incoming Car Probability must be greater or equal to zero or less or equal to 1", "Input Error",
					JOptionPane.ERROR_MESSAGE);
		}
	}

	public void safeSleep(long milliseconds) {
		try {
			Thread.sleep(milliseconds);
		}
		catch (InterruptedException e) {

		}
	}
}

